﻿using System.Windows;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Media;
using System.Windows.Shapes;

namespace ThePresenter.Windows.Controls
{
	class DropPreviewAdorner : Adorner
	{
		#region Fields

		Rectangle _PreviewElement;

		Point _CenterOffset;

		TranslateTransform _Position;

		#endregion

		#region Properties

		/// <summary>
		/// Gets the number of visual child elements within this element.
		/// </summary>
		/// <value></value>
		/// <returns>The number of visual child elements for this element.</returns>
		protected override int VisualChildrenCount
		{
			get
			{
				return 1;
			}
		}

		#endregion

		#region Constructors

		/// <summary>
		/// Initializes a new instance of the <see cref="DropPreviewAdorner"/> class.
		/// </summary>
		/// <param name="owner">The owner.</param>
		/// <param name="strokes">The strokes.</param>
		/// <param name="InitialPoint">The initial point.</param>
		public DropPreviewAdorner(UIElement owner, StrokeCollection strokes, Point InitialPoint)
			: base(owner)
		{
			_Position = new TranslateTransform(InitialPoint.X, InitialPoint.Y);

			_PreviewElement = new Rectangle();

			Rect size = strokes.GetBounds();
			_PreviewElement.Width = size.Width;
			_PreviewElement.Height = size.Height;

			ImageBrush brush = new ImageBrush(Data.Shape.GetThumbnail(strokes, size.Size));
			brush.Opacity = 0.5;
			_PreviewElement.Fill = brush;

			_CenterOffset = new Point(-(_PreviewElement.Width / 2), -(_PreviewElement.Height / 2));

			owner.PreviewDragOver += new DragEventHandler(Owner_PreviewDragOver);
		}

		#endregion

		#region Methods

		/// <summary>
		/// Implements any custom measuring behavior for the adorner.
		/// </summary>
		/// <param name="constraint">A size to constrain the adorner to.</param>
		/// <returns>A <see cref="T:System.Windows.Size"/> object representing the amount of layout space needed by the adorner.</returns>
		protected override Size MeasureOverride(Size constraint)
		{
			_PreviewElement.Measure(constraint);

			return _PreviewElement.DesiredSize;
		}

		/// <summary>
		/// When overridden in a derived class, positions child elements and determines a size for a <see cref="T:System.Windows.FrameworkElement"/> derived class.
		/// </summary>
		/// <param name="finalSize">The final area within the parent that this element should use to arrange itself and its children.</param>
		/// <returns>The actual size used.</returns>
		protected override Size ArrangeOverride(Size finalSize)
		{
			_PreviewElement.Arrange(new Rect(finalSize));

			return finalSize;
		}

		/// <summary>
		/// Overrides <see cref="M:System.Windows.Media.Visual.GetVisualChild(System.Int32)"/>, and returns a child at the specified index from a collection of child elements.
		/// </summary>
		/// <param name="index">The zero-based index of the requested child element in the collection.</param>
		/// <returns>
		/// The requested child element. This should not return null; if the provided index is out of range, an exception is thrown.
		/// </returns>
		protected override Visual GetVisualChild(int index)
		{
			return _PreviewElement;
		}

		/// <summary>
		/// Updates the position.
		/// </summary>
		private void UpdatePosition()
		{
			AdornerLayer adornerLayer = this.Parent as AdornerLayer;

			if (adornerLayer != null)
			{
				adornerLayer.Update();
			}
		}

		/// <summary>
		/// Returns a <see cref="T:System.Windows.Media.Transform"/> for the adorner, based on the transform that is currently applied to the adorned element.
		/// </summary>
		/// <param name="transform">The transform that is currently applied to the adorned element.</param>
		/// <returns>A transform to apply to the adorner.</returns>
		public override GeneralTransform GetDesiredTransform(GeneralTransform transform)
		{
			GeneralTransformGroup result = new GeneralTransformGroup();

			result.Children.Add(_Position);
			result.Children.Add(base.GetDesiredTransform(transform));

			return result;
		}

		#endregion

		#region Event handlers

		/// <summary>
		/// Handles the PreviewDragOver event of the Owner control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.DragEventArgs"/> instance containing the event data.</param>
		private void Owner_PreviewDragOver(object sender, DragEventArgs e)
		{
			Point MousePosition = e.GetPosition(sender as UIElement);

			_Position.X = MousePosition.X + _CenterOffset.X;
			_Position.Y = MousePosition.Y + _CenterOffset.Y;

			UpdatePosition();
		}

		#endregion
	}
}